# -*- encoding: utf-8 -*-
"""
@File  :   esapi.py
@Time  :   2022-06-26
flask api 接口
"""

import win32serviceutil
import win32service
import win32event
from flask import Flask
from flask import Flask, request, jsonify
import sys
import os
import zipfile
# import requests
import shutil
import re
import threading
import time
import datetime
import logging
import inspect
import subprocess
from threading import Timer
from logging.handlers import TimedRotatingFileHandler
import uuid
import hashlib
import win32api
import sqlite3

LOCK = threading.Lock()

def dict_factory(cursor, row):  
  # 重写row_factory方法，实现拉取字典结构数据
  d = {}  
  for idx, col in enumerate(cursor.description):  
    d[col[0]] = row[idx]  
  return d  

class dbconn():
  def __init__(self,dbname):   
    isNewDb = False if os.path.exists(dbname) else True
    connParms = self.ConnectDb(dbname)

    if connParms:
      self.conn,self.cur = connParms
      self.isConnect = True
      if isNewDb:self.InitDb() # 新数据库初始化数据
    else:
      self.isConnect = False
   
  def __del__(self):
    self.conn.close()

  def ConnectDb(self,db):    
    try:
      conn = sqlite3.connect(db, timeout=3, isolation_level=None,check_same_thread=False) 
      conn.row_factory = dict_factory
      cur = conn.cursor()     
      return conn,cur
    except BaseException as e:
      print("connectDb err:", e)
      return False

  # 新增记录单条记录
  def InsertRow(self, table, items):      
    # table:表格名称
    # items:字典数据
    try:
      LOCK.acquire(True)
      fields = ','.join([x for x in items])
      values = ','.join([f"'{items[key]}'" for key in items])
      sql = f"INSERT INTO {table} ({fields}) VALUES ({values})"
      self.cur.execute(sql)    
      self.conn.commit()
      return {'code':"0","data":"insert success!"}
    except Exception as e:
      return {'code':"-1","data":e.__str__()}
    finally:
      LOCK.release()

  # SQL语句执行
  def Exec(self,scripts):      
    # scripts：检索语句
    # print(scripts)
    try:
      LOCK.acquire(True)
      self.cur.execute(scripts)
      _data = self.cur.fetchall()   

      return {'code':"0","data":_data}
    except Exception as e:
      return {'code':"-1","data":e.__str__()}
    finally:
      LOCK.release()
    # return {'code':"-1","data":scripts}    

  def InitDb(self):
    sql = '''
    CREATE TABLE test (id TEXT PRIMARY KEY NOT NULL, item TEXT NOT NULL)
    '''
    self.cur.execute(sql)
    self.conn.commit()  




# 获取当前路径
def getCurrentPath():
  path = sys.argv[0].split('\\')
  path.pop()
  path = '\\'.join(path) + "\\"
  return path

def getBakPath():
   pass

def bakFileExists(path, fname):
  if not os.path.exists(path):
    os.makedirs(path)
  return os.path.exists(fname)


def backup(dbname, fname):
  pass

class myservice(win32serviceutil.ServiceFramework):
  # windows服务名称相关
  _svc_name_ = 'esapi'  # 任务管理器中显示的服务名
  _svc_display_name_ = '电子报告归档接口'  # 服务管理器中显示的名称
  _svc_description_ = '电子报告归档接口'  # 服务管理器中显示的说明

  def __init__(self, args):
    win32serviceutil.ServiceFramework.__init__(self, args)
    self.logger = self._getLogger()
    self.stop_event = win32event.CreateEvent(None, 0, 0, None)
    self.port = 10123
    

  def _getLogger(self):
    '''日志记录'''
    logger = logging.getLogger('@')
    this_file = inspect.getfile(inspect.currentframe())
    dirpath = os.path.abspath(os.path.dirname(this_file))
    if os.path.isdir('c:\\log'):  # 创建log文件夹
      pass
    else:
      os.mkdir('c:\\log')
    dir = 'c:\\log'
    handler = TimedRotatingFileHandler(os.path.join(dir, "esapi.log"),
      when="midnight",
      interval=1,
      backupCount=20)
    # formatter = logging.Formatter(
    #   '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
    formatter = logging.Formatter(
      '%(asctime)s %(levelname)-8s %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.setLevel(logging.INFO)
    return logger

  # 服务程序主逻辑
  def SvcDoRun(self):
    logwriter = self.logger
    app = Flask(__name__)   

    @app.route('/db/exec', methods=['POST'])
    def db_exec():
      _data = request.get_json()
      res = db.Exec(_data["sql"])
      return jsonify(res)

    @app.route('/db/insertrow', methods=['POST'])
    def db_insertrow():
      _data = request.get_json() 
      res = db.InsertRow(_data["table"],_data["items"])    
      return jsonify(res)


    @app.route('/db/addTask', methods=['POST'])
    def db_addtask():
      _data = request.get_json()    
      _values = _data["_reports"]    
      _sql = "insert into report " + _values      
      db.Exec(_sql)  
      res = db.InsertRow("task",_data["_task"])  
      return jsonify({'code':"0","data":_data["_task"]})

    @app.route('/db/taskIsExist', methods=['POST'])
    def db_taskIsExist():
      _data = request.get_json() 
      orgFileLis = _data["fileList"]
      params = ",".join([f"'{x}'" for x in orgFileLis])
      sql = f"select path from task where path in ({params}) "
      _res = db.Exec(sql)
      print(_res)
      for p in _res["data"]:
        print(p)
        orgFileLis.remove(p["path"])

      return jsonify(orgFileLis) 
            
    @app.route("/")
    @app.route("/index")
    def index():
      return "报告归档本地API V1.1"

    logwriter.info("esapi 服务启动")
    # 启动flask 监听本地端口 响应请求
    app.run(host='0.0.0.0', port=self.port)  
    
  def SvcStop(self):
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    win32event.SetEvent(self.stop_event)
    self.ReportServiceStatus(win32service.SERVICE_STOPPED)
    self.logger.info("esapi 服务停止")


if __name__ == '__main__':
  import sys
  import servicemanager    

  _config = {
    "database":"d:/esapidb/database.db"
  }

  """
    数据库默认保存到 d:/esapidb/database.db
    通过修改C盘esapicfg.data文件实现自定义保存路径    
  """

  if os.path.exists("c:\\esapicfg.data"): 
    with open("c:\\esapicfg.data") as f:
      _config = eval(f.read())
  else:
    with open("c:\\esapicfg.data",'w') as f:
      f.write(str(_config))

  db = dbconn(_config["database"]) 

  if len(sys.argv) == 1:
    # myservice 为服务的类名称 需要与上方声明一致
    try:
      evtsrc_dll = os.path.abspath(servicemanager.__file__)
      servicemanager.PrepareToHostSingle(myservice)
      servicemanager.Initialize('myservice', evtsrc_dll)
      servicemanager.StartServiceCtrlDispatcher()
    except win32service.error as details:
      import winerror
      if details == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
        win32serviceutil.usage()
  else:
    win32serviceutil.HandleCommandLine(myservice)